home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Technotools
/
Technotools (Chestnut CD-ROM)(1993).ISO
/
os2tools
/
aping
/
aping.c
< prev
next >
Wrap
Text File
|
1992-06-14
|
27KB
|
763 lines
/*****************************************************************************
*
* MODULE NAME : APING.C
*
* COPYRIGHTS:
* This module contains code made available by IBM
* Corporation on an AS IS basis. Any one receiving the
* module is considered to be licensed under IBM copyrights
* to use the IBM-provided source code in any way he or she
* deems fit, including copying it, compiling it, modifying
* it, and redistributing it, with or without
* modifications. No license under any IBM patents or
* patent applications is to be implied from this copyright
* license.
*
* A user of the module should understand that IBM cannot
* provide technical support for the module and will not be
* responsible for any consequences of use of the program.
*
* Any notices, including this one, are not to be removed
* from the module without the prior written consent of
* IBM.
*
* AUTHOR: Peter J. Schwaller
* VNET: PJS at RALVM6 Tie Line: 444-4376
* Internet: pjs@ralvm6.vnet.ibm.com (919) 254-4376
*
* FUNCTION: Perform an echo test to a specified destination.
* APING can be used when you are first installing APPC on
* your computer to make sure you can connect to another
* computer in the network. APING can also be used to
* get an estimate of the delay time or throughput to another
* computer in the network.
*
* AVAILABILITY:
* These sample programs and source are also available on
* CompuServe through the APPC Information Exchange. To get
* to the APPC forum just type 'GO APPC' from any CompuServe
* prompt. The samples are available in the Sample Programs
* library section. Just search on the keyword CPICPGMS to
* find all the samples in this series.
*
* Updates for the sample programs and support for many more
* CPI-C platforms will also be made available on CompuServe.
*
* RELATED FILES:
* See APING.DOC for detailed information.
*
*****************************************************************************/
/*****************************************************************************
* OVERVIEW of APING CPI-C Flows
*
* Client (APING) Server (APINGD)
* -------------- ---------------
* Set up conversation
* Allocate -------------------> Accept Conversation
* Exchange Version Numbers
* Send Data -------------------> Receive
* Receive <------------------- Send Data
* For number of iterations (i)
* For number of consecutive packets (c)
* Send Data -------------------> Receive
* For number of consecutive packets (c)
* Receive <------------------- Send Data
* Shut down the conversation
* Deallocate (FLUSH)
*****************************************************************************/
/* The following definitions are needed for VM and MVS */
#if defined(VM) || defined(MVS)
/* All arguments on the command line should be passed to this program. */
#pragma runopts(noexecops)
/* The C/370 compiler requires that identifier be unique in the 1st 8 chars. */
#define current_iteration curr_iteration
#define current_concurrent curr_concurrent
#endif
/* My CPI-C include file */
/* Hides CMC.H differences among platforms */
#include "cpiccmc.h"
/* Collection of routines with special ported version for each platform */
#include "cpicport.h"
/* standard C include files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#ifndef TIME_NOT_SUPPORTED
#ifndef AIX
#include <time.h>
#else
#include <sys/time.h>
#endif
#endif
/* CPI-C error handling routines */
/* This file is supplied with APING */
#include "cpicerr.h"
/* CPI-C initialization routines */
/* This file is supplied with APING */
#include "cpicinit.h"
/* Argument processing procedure */
/* This file is supplied with APING */
#include "getopt.h"
/* CPI-C error handling info */
CPICERR * cpicerr;
/*
* Max size of a data buffer. This is the largest size buffer that can
* be specified on a call to CPI-C.
*/
#define MAX_SIZE (0x7FFF)
/* These are the defaults to be used if the user does not provide arguments */
/* to override these values. */
#define DEFAULT_TP_NAME "APINGD"
#define DEFAULT_PARTNER "NETID.LUNAME"
#define DEFAULT_MODE_NAME "#INTER"
#define DEFAULT_SYM_DEST "APINGD"
/* Define these here so we can make changes throughout the code. */
#define PROGRAM_NAME "APING"
#define PROGRAM_INFO "version 2.2"
#define MAJOR_VERSION (2)
#define MINOR_VERSION (2)
#define LOG_FILE_NAME "aping.err"
#define LOG_FILE_PATH "$LOGPATH"
#define ONEWAY_MAJOR_VERSION (2)
#define ONEWAY_MINOR_VERSION (2)
/* function prototypes for procedures in this file */
void exit_processing(void);
void handler(int);
void process_arguments(int argc,
char *argv[],
CPICINIT * cpicinit);
#ifndef TIME_NOT_SUPPORTED
ULONG get_time(void);
#endif
/*
* The following variables are global to enable their use by the
* exit_processing() subroutine.
*/
ULONG number_iterations = 2; /* times through the loop */
ULONG number_concurrent = 1; /* sends by each side per loop */
ULONG current_iteration; /* which iteration is active */
ULONG current_concurrent; /* which send/recv is active */
#ifndef TIME_NOT_SUPPORTED
ULONG total_time = 0; /* used to calculate averages */
ULONG min_time = 0xFFFFFFFF; /* used for max elapsed time */
ULONG max_time = 0; /* used for min elapsed time */
double data_rate; /* Variable used to calculate */
/* the data rate */
#endif
ULONG size = 100; /* size of data sends */
int one_way_flag = 2; /* Was one way data requested */
/* value of 2 means two way echo */
/* value of 1 means one way */
/*
* Message displayed with show_info() when APING is started.
*/
char * intro[] = {
PROGRAM_NAME " " PROGRAM_INFO " APPC echo test with timings.",
" by Peter J. Schwaller (pjs@ralvm6.vnet.ibm.com)",
NULL
};
/*
* Message displayed with show_info() when usage information is requested or
* after an invalid flag was specified.
*/
char * usage[] = {
"",
"APING [flags] destination",
" destination",
"\tmay be either a symbolic destination name or a partner LU name",
" -m mode_name",
"\tmode name (default: #BATCH)",
" -t tp_name",
"\tthe TP to start on the server (default: APINGD)",
" -s N",
"\tN is the size of the packet transmitted (default: 100 bytes)",
" -i N",
"\tN is the number of iterations (default: 2)",
" -c N",
"\tN is the number of consecutive packets sent by each side (default: 1)",
" -1",
"\tOnly send data from client to server (No echo)",
" -u userid",
" -p password",
"\tSecurity parameters. If a userid is specified without a password,",
"\tyou will be prompted for the password.",
" -n",
"\tDo not use any security (SECURITY=NONE).",
"",
#ifndef TIME_NOT_SUPPORTED
"The minimum time, maximum time, and average time will be shown.",
#endif
NULL
};
void cdecl
main( int argc, char *argv[])
{
/* Variables used for CPI-C calls */
unsigned char cm_conv_id[8]; /* CPI-C conversation ID */
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
CM_INT32 max_receive_len; /* Max receive length on CMRCV */
CM_INT32 what_received; /* What received parm from CMRCV */
CM_INT32 received_len; /* Amount of data rcvd on CMRCV */
CM_INT32 status_received; /* Status from CMRCV */
/* Data buffer for send and receive */
unsigned char CM_PTR buffer; /* CPIC data buffer */
/* Destination information */
CPICINIT * cpicinit;
#ifndef TIME_NOT_SUPPORTED
ULONG start_time = 0; /* when a ping starts */
ULONG end_time; /* when a ping ends */
ULONG elapsed_time; /* used for time calculations */
#endif
char partner_major_version;
char partner_minor_version;
/*
* Make sure all output is seen as soon as possible.
*/
setbuf(stdout, NULL);
show_info(intro); /* Show program information */
/*
* Create a new CPICINIT structure and initialize values.
* The procedures are in CPICINIT.C
*/
cpicinit = cpicinit_new();
cpicinit_default_tp_name(cpicinit, DEFAULT_TP_NAME);
cpicinit_default_destination(cpicinit, DEFAULT_PARTNER);
cpicinit_default_mode_name(cpicinit, DEFAULT_MODE_NAME);
cpicinit_default_sym_dest_name(cpicinit, DEFAULT_SYM_DEST);
/*
* Process all of the command line arguments. All of the conversation
* setup arguments are stored in the cpicinit object. The block size
* and other loop parameters are set in the global variables.
*/
process_arguments(argc, argv, cpicinit);
if (cpicinit->set_destination == NOT_SET) {
fprintf(stderr, "\n\aYou must specify a destination.\n");
show_info(usage);
exit(EXIT_FAILURE);
}
if (cpicinit_query_passwd_required(cpicinit)) {
/* get a password from the user */
cpicinit_get_passwd(cpicinit);
}
#if 0
/* set up a signal handler, to clean up and display total upon exit */
if (signal(SIGINT, SIG_IGN) == SIG_DFL)
signal(SIGINT, handler);
#endif
buffer = (unsigned char CM_PTR)alloc_cpic_buffer((USHORT)size);
/* allocate an APPC buffer */
/*
* Initialize the CPICERR structure. This is done before the CMINIT
* call so that we can use CPICERR for help with errors on CMINIT.
* The procedure is in CPICERR.C
*/
cpicerr = cpicerr_new();
cpicerr_set_program_name(cpicerr, PROGRAM_NAME);
cpicerr_set_program_info(cpicerr, PROGRAM_INFO);
cpicerr_set_major_version(cpicerr, MAJOR_VERSION);
cpicerr_set_minor_version(cpicerr, MINOR_VERSION);
cpicerr_set_log_file_name(cpicerr, LOG_FILE_NAME);
cpicerr_set_log_file_path(cpicerr, LOG_FILE_PATH);
cpicinit_setup_conversation(cpicinit, cm_conv_id, cpicerr);
/*
* Fill in conversation information for CPI-C error reporting.
*/
cpicerr_set_conv_id(cpicerr, cm_conv_id);
{
CM_SYNC_LEVEL sync_level = CM_CONFIRM;
cmssl(cm_conv_id, /* Set sync level */
&sync_level,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSSL, cm_rc);
}
{
CM_PREPARE_TO_RECEIVE_TYPE prep_to_receive = CM_PREP_TO_RECEIVE_FLUSH;
cmsptr(cm_conv_id, /* Set prepare to receive type */
&prep_to_receive,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSPTR, cm_rc);
}
/*
* Fill in conversation information for CPI-C error reporting.
*/
cpicerr_set_conv_id(cpicerr, cm_conv_id);
#ifndef TIME_NOT_SUPPORTED
start_time = get_time(); /* let's time the allocate */
#endif
cmallc(cm_conv_id,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMALLC, cm_rc);
#ifndef TIME_NOT_SUPPORTED
end_time = get_time(); /* stop the timer */
/* show the allocate time */
printf("\nAllocate duration: %8lu ms\n",
end_time - start_time);
#endif
#ifndef TIME_NOT_SUPPORTED
start_time = get_time();
#endif
cpicerr_exchange_version(cpicerr,
cm_conv_id,
CM_SEND_STATE,
&partner_major_version,
&partner_minor_version);
/*
* If the one_way_flag has been set, we have to make sure that our
* partner is at the correct version to accept one way data. If
* the partner is not at the right level, we'll turn off the one
* way flag and the partner will echo data (normal operating mode).
*
* Trying to use one way data with a partner that can't handle the
* CONFIRM status indicator would result in an error on the partner
* side. On this side, we would see DEALLOCATE_ABEND.
*/
if ((one_way_flag == 1) &&
!(partner_major_version > ONEWAY_MAJOR_VERSION ||
(partner_major_version == ONEWAY_MAJOR_VERSION &&
partner_minor_version >= ONEWAY_MINOR_VERSION))) {
printf("\nOne way data transfer is not supported by partner.\n");
printf("Partner will echo data.\n");
one_way_flag = 2;
}
#ifndef TIME_NOT_SUPPORTED
end_time = get_time(); /* stop the timer */
/* show the startup time */
printf("\nProgram startup and Confirm duration: %8lu ms\n\n",
end_time - start_time);
#endif
printf(
" Duration Data Sent Data Rate Data Rate\n");
printf(
" (msec) (bytes) (KB/s) (Mb/s) \n");
printf(
" -------- --------- --------- ---------\n");
/*
* Start current at zero so if a BREAK occurs, it will contain the number
* of iterations completed. We take a slight risk in assuming that
* the current_iteration++ operation is atomic.
*
* This loop encompasses both a send loop and a receive loop. Both
* the send a receive loop are executed the number of times specified
* by the number_iterations variable (set by the -i argument).
*/
for (current_iteration = 0;
current_iteration<number_iterations;
current_iteration++ ) {
{
CM_SEND_TYPE send_type = CM_BUFFER_DATA;
cmsst(cm_conv_id,
&send_type,
&cm_rc);
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
}
#ifndef TIME_NOT_SUPPORTED
start_time = get_time();
#endif
for (current_concurrent = 1; /* Start current at one so we */
current_concurrent<number_concurrent ; /* do one LESS send in */
current_concurrent++ ) { /* loop than the specifed number */
length = size;
cmsend(cm_conv_id,
buffer,
&length,
&rts_received,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
}
/*
* Set the send type to do a send and a prepare to receive. This will
* send both the data and the send permission indicator to our
* partner all at once.
*
* If the one_way_flag has been set, we will issue a Confirm along
* with the Send_Data. This will allow us to know when the partner
* has actually received all the data so we can get an accurate
* timing.
*
* On the partner side, if Send status is received, the partner will
* know to echo the data. If Confirm status is received, the partner
* will know to issued Confirmed and then get ready to receive
* more data, since the partner won't be echoing.
*/
{
CM_SEND_TYPE send_type;
if (one_way_flag != 1) {
send_type = CM_SEND_AND_PREP_TO_RECEIVE;
} else {
send_type = CM_SEND_AND_CONFIRM;
}
cmsst(cm_conv_id,
&send_type,
&cm_rc);
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSST, cm_rc);
}
length = size;
cmsend(cm_conv_id,
buffer,
&length,
&rts_received,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
if (one_way_flag != 1) {
max_receive_len = size;
do {
cmrcv (cm_conv_id, /* Receive Data */
buffer, /* Data Pointer */
&max_receive_len, /* Size of Data Buffer */
&what_received, /* returned - what received */
&received_len, /* returned - length of data */
&status_received, /* returned - status received */
&rts_received, /* returned - request to send */
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) {
cpicerr_handle_rc(cpicerr, MSG_CMRCV, cm_rc);
}
if (what_received != CM_NO_DATA_RECEIVED) {
current_concurrent--;
}
} while ((status_received != CM_SEND_RECEIVED));
/* Repeat the receive loop until SEND permission has been rcvd. */
if (current_concurrent != 0) {
fprintf(stderr,
"ERROR.\n");
fprintf(stderr,
"Partner did not send the expected number of records.\n");
}
} else {
}
#ifndef TIME_NOT_SUPPORTED
end_time = get_time(); /* stop timer */
elapsed_time = end_time - start_time; /* calculate elapsed time */
printf("%16ld", elapsed_time);
printf("%17lu", size * number_concurrent * one_way_flag);
if (elapsed_time) {
data_rate = /* in KBytes / 0.1 Sec */
(double)
( ( (((double)size * (double)number_concurrent) / (double)1024) *
(double)1 * (double)1000 * (double)one_way_flag)
/ /* divided by */
( (double)elapsed_time / (double)10) );
data_rate = data_rate / (double)10;
printf("%17.1f", data_rate);
printf("%17.3f\n", (data_rate * (double)8) / (double)1000);
} else {
printf("\n"); /* Make sure we move to next line*/
}
total_time += elapsed_time; /* accumulate the elapsed time */
if (elapsed_time > max_time) {
max_time = elapsed_time; /* set the max time */
}
if (elapsed_time < min_time) {
min_time = elapsed_time; /* set the min time */
}
#else
printf("Ping completed\n");
#endif
}
{
CM_DEALLOCATE_TYPE deallocate_type = CM_DEALLOCATE_FLUSH;
cmsdt(cm_conv_id,
&deallocate_type,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMSDT, cm_rc);
}
cmdeal(cm_conv_id,
&cm_rc);
/* The only expected return code is CM_OK */
if (cm_rc != CM_OK) cpicerr_handle_rc(cpicerr, MSG_CMDEAL, cm_rc);
/* destroy the object we created with cpicinit_new() */
cpicinit_destroy(cpicinit);
/* destroy the object we created with cpicerr_new() */
cpicerr_destroy(cpicerr);
exit_processing(); /* to avoid losing printouts */
/* if redirected. */
exit(EXIT_SUCCESS); /* force exit_list processing */
}
void
process_arguments(int argc,
char *argv[],
CPICINIT * cpicinit)
{
int c; /* flag specifed, used w/getopt */
/*
* GETOPT is an easy way to parse command line arguments
* Each parameter which can have a flag is passed in the third argument
* to getopt. Getopt returns the character of the flag on the command
* line and sets optarg to point to the value associated with the flag.
* optind is the index of the argument that getopt is currently processing.
*/
while (optind != argc) {
c = getopt(argc, argv, "?1c:t:m:i:s:u:p:C:T:M:I:S:U:P:nN");
switch (c) {
case EOF:
optarg = argv[optind];
if (optarg[0] == '?') {
show_info(usage);
exit(EXIT_FAILURE);
}
optind++;
if (cpicinit->set_destination == NOT_SET) {
cpicinit_set_destination(cpicinit, optarg);
} else {
fprintf(stderr, "Only one destination may be specified.\n");
}
break;
case 'M':
case 'm':
cpicinit_set_mode_name(cpicinit, optarg);
break;
case 'T':
case 't':
cpicinit_set_tp_name(cpicinit,optarg);
break;
case 'U':
case 'u':
cpicinit_set_userid(cpicinit, optarg);
break;
case 'P':
case 'p':
cpicinit_set_passwd(cpicinit, optarg);
break;
case 'N':
case 'n':
cpicinit_set_security_none(cpicinit);
break;
case 'S':
case 's':
size = atol(optarg); /* get the size of send blocks */
if (size > MAX_SIZE) { /* check bounds */
printf("Size (-s) of %lu too large.\n"
"Setting to %lu\n", size, (unsigned long)MAX_SIZE);
size = MAX_SIZE; /* reset to MAX */
}
break;
case 'I':
case 'i':
number_iterations = atol(optarg);
break;
case 'C':
case 'c':
number_concurrent = atol(optarg);
break;
case '1':
one_way_flag = 1;
break;
case '?':
show_info(usage);
exit(EXIT_FAILURE);
break;
default:
printf("Invalid flag. Use %s -? for usage\n", PROGRAM_NAME);
exit(EXIT_FAILURE);
}
}
}
#ifndef TIME_NOT_SUPPORTED
ULONG
/* returns time in milliseconds */
get_time(void)
{
#if defined(OS2) || defined(FAPI) || defined(DOS)
/*
* clock() returns valid information on OS/2 and DOS since no distinction
* is made between process time and time of day.
*/
clock_t time;
time = clock();
return (time / (CLK_TCK / 1000));
#elif defined(AIX)
time_t ltime;
struct timestruc_t TimeStruct;
if (gettimer(TIMEOFDAY, &TimeStruct) == 0) {
return ((1000 * TimeStruct.tv_sec) + (TimeStruct.tv_nsec / 1000000));
} else {
time(<ime);
return 1000 * ltime;
}
#else
/*
* Other systems must use the time() calls to get the time of day in
* seconds. This results in very coarse timings.
*/
time_t ltime;
time(<ime);
return 1000 * ltime;
#endif
}
#endif
void handler(int sig)
{
/*=========================================================================
* This is the signal handler.
* Input parameter "sig" is not used, but required by the function
* prototype for the signal() library call.
*=======================================================================*/
(void)signal(SIGINT, SIG_IGN);
exit_processing();
exit(EXIT_FAILURE);
}
void exit_processing(void)
/*
* Print out the grand totals and max/min times.
*/
{
double data_rate;
static int beenhere = 0;
#ifndef TIME_NOT_SUPPORTED
if (!beenhere) { /* avoid being printing twice */
beenhere = 1;
if (total_time > 10) {
data_rate = /* in KBytes / 0.1 Sec */
(double)
( ( (((double)size * (double)number_concurrent) / (double)1024) *
(double)current_iteration * (double)1000 * (double)one_way_flag)
/ /* divided by */
( (double)total_time / (double)10) );
data_rate = data_rate / 10;
printf("Totals:%9lu", total_time);
printf("%17lu", size *
number_concurrent *
current_iteration *
one_way_flag);
printf("%17.1f", data_rate);
printf("%17.3f\n", (data_rate * (double)8) / (double)1000);
if (current_iteration > 0) {
printf(
"\nDuration statistics: Min = %lu Ave = %lu Max = %lu\n",
min_time,
total_time / current_iteration,
max_time);
}
} else {
printf("\n");
}
}
#endif
}